```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Java持久化技术：JPA与Spring Data JPA详解</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Noto Sans SC', 'Noto Serif SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.6;
        }
        h1, h2, h3, h4 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
        }
        .hero-gradient {
            background: linear-gradient(135deg, #6B73FF 0%, #000DFF 100%);
        }
        .code-block {
            background-color: #282c34;
            border-radius: 0.5rem;
            padding: 1.25rem;
            font-family: 'Fira Code', monospace;
            position: relative;
        }
        .code-block pre {
            margin: 0;
            overflow-x: auto;
        }
        .code-block:before {
            content: '';
            position: absolute;
            top: 0;
            right: 0;
            width: 100%;
            height: 2rem;
            background-color: rgba(255, 255, 255, 0.1);
            border-top-left-radius: 0.5rem;
            border-top-right-radius: 0.5rem;
        }
        .code-block:after {
            content: '';
            position: absolute;
            top: 0.5rem;
            right: 1rem;
            width: 0.75rem;
            height: 0.75rem;
            background-color: #ff5f56;
            border-radius: 50%;
            box-shadow: 1rem 0 0 #ffbd2e, 2rem 0 0 #27c93f;
        }
        .highlight-box {
            border-left: 4px solid #4f46e5;
            background-color: #f8fafc;
            padding: 1.5rem;
            margin: 1.5rem 0;
            border-radius: 0 0.375rem 0.375rem 0;
        }
        .hover-scale {
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }
        .hover-scale:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .text-gradient {
            background: linear-gradient(90deg, #4f46e5, #10b981);
            -webkit-background-clip: text;
            background-clip: text;
            color: transparent;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="hero-gradient text-white py-20 md:py-32">
        <div class="container mx-auto px-6 max-w-6xl">
            <div class="flex flex-col md:flex-row items-center">
                <div class="md:w-1/2 mb-10 md:mb-0">
                    <h1 class="text-4xl md:text-5xl font-bold mb-6">Java持久化技术详解</h1>
                    <h2 class="text-2xl md:text-3xl font-semibold mb-6"><span class="text-gradient">JPA & Spring Data JPA</span></h2>
                    <p class="text-xl opacity-90 mb-8">探索Java世界中最强大的ORM规范及其Spring生态系统实现</p>
                    <div class="flex space-x-4">
                        <a href="#what-is-jpa" class="bg-white text-indigo-600 px-6 py-3 rounded-lg font-medium hover:bg-gray-100 transition duration-300">
                            <i class="fas fa-book mr-2"></i>开始学习
                        </a>
                        <a href="http://www.yuque.com/jtostring" target="_blank" class="border-2 border-white px-6 py-3 rounded-lg font-medium hover:bg-white hover:text-indigo-600 transition duration-300">
                            <i class="fas fa-external-link-alt mr-2"></i>技术小馆
                        </a>
                    </div>
                </div>
                <div class="md:w-1/2 flex justify-center">
                    <img src="https://cdn.nlark.com/yuque/0/2024/png/21449790/1707881505810-62211968-6f4b-44a7-a988-c31e4d7a02c0.png" alt="JPA架构图" class="w-full max-w-md rounded-lg shadow-2xl hover-scale">
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto px-6 py-12 max-w-6xl">
        <!-- What is JPA -->
        <section id="what-is-jpa" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">1. 什么是JPA</h2>
            </div>
            <div class="prose max-w-none text-gray-700">
                <p class="text-lg mb-6">JPA (Java Persistence API) 是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。</p>
                <p class="mb-6">它的出现主要是为了简化现有的持久化开发工作和整合ORM技术，改变Hibernate、TopLink、JDO等ORM框架各自为营的局面。<span class="font-semibold text-indigo-600">简单来说，JPA是一套规范、标准，而HibernateJPA是其中一种实现。</span></p>
                
                <div class="my-8">
                    <img src="https://cdn.nlark.com/yuque/0/2024/png/21449790/1707881505810-62211968-6f4b-44a7-a988-c31e4d7a02c0.png" alt="JPA架构图" class="w-full rounded-lg shadow-md hover-scale">
                </div>
                
                <p class="mb-6">与JDBC类似，JPA统一了Java应用程序访问ORM框架的规范。以前我们的应用程序直接使用ORM框架，如Hibernate、MyBatis。但是不同的ORM框架使用方法不一样，而JPA让我们以同样的方式访问不同的ORM框架。常用的框架是HibernateJPA。</p>
                
                <div class="highlight-box">
                    <h4 class="font-bold text-xl mb-4 text-indigo-600"><i class="fas fa-exclamation-circle mr-2"></i>关键点</h4>
                    <p class="text-red-600 font-semibold">JPA是一个规范，不是框架，HibernateJPA这是一个JPA的实现</p>
                </div>
            </div>
        </section>

        <!-- Why use JPA -->
        <section id="why-use-jpa" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">2. 为什么要使用JPA</h2>
            </div>
            <div class="grid md:grid-cols-2 gap-6">
                <div class="bg-white p-6 rounded-xl shadow-md hover-scale">
                    <div class="text-indigo-600 text-2xl mb-4">
                        <i class="fas fa-stream"></i>
                    </div>
                    <h3 class="text-xl font-semibold mb-3">简化数据持久化</h3>
                    <p>JPA提供了一种简单而强大的方式来管理Java对象与数据库之间的映射关系，大大简化了数据持久化的处理过程。开发人员可以通过JPA注解来描述对象-关系映射，而不需要编写繁琐的SQL语句。</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-md hover-scale">
                    <div class="text-indigo-600 text-2xl mb-4">
                        <i class="fas fa-rocket"></i>
                    </div>
                    <h3 class="text-xl font-semibold mb-3">提高开发效率</h3>
                    <p>使用JPA可以减少开发人员编写重复性的数据访问代码的时间和工作量。通过JPA提供的API，开发人员可以使用简洁的语法进行数据的增删改查操作，大大提高了开发效率。</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-md hover-scale">
                    <div class="text-indigo-600 text-2xl mb-4">
                        <i class="fas fa-database"></i>
                    </div>
                    <h3 class="text-xl font-semibold mb-3">数据库无关性</h3>
                    <p>JPA提供了一种抽象的数据访问接口，使得应用程序与具体的数据库实现解耦。开发人员可以在不修改代码的情况下轻松地切换数据库，从而提高了系统的灵活性和可维护性。</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-md hover-scale">
                    <div class="text-indigo-600 text-2xl mb-4">
                        <i class="fas fa-cube"></i>
                    </div>
                    <h3 class="text-xl font-semibold mb-3">面向对象编程模型</h3>
                    <p>JPA支持面向对象的编程模型，开发人员可以直接使用Java对象来表示业务实体，而不需要关注数据库表的细节。这种面向对象的编程模型使得数据持久化操作更加直观和易于理解。</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-md hover-scale md:col-span-2">
                    <div class="text-indigo-600 text-2xl mb-4">
                        <i class="fas fa-shield-alt"></i>
                    </div>
                    <h3 class="text-xl font-semibold mb-3">支持事务管理</h3>
                    <p>JPA支持事务管理，开发人员可以使用注解或者编程方式来管理事务，保证数据的一致性和完整性。</p>
                </div>
            </div>
        </section>

        <!-- JPA Features -->
        <section id="jpa-features" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">3. JPA的特征</h2>
            </div>
            <div class="prose max-w-none text-gray-700">
                <div class="grid md:grid-cols-2 gap-6 mb-8">
                    <div class="bg-white p-6 rounded-xl shadow-md">
                        <h3 class="text-xl font-semibold mb-3 text-indigo-600">实体注解</h3>
                        <p>JPA使用实体注解来描述Java对象与数据库表之间的映射关系，包括实体类的声明、主键的定义、字段的映射等。</p>
                    </div>
                    <div class="bg-white p-6 rounded-xl shadow-md">
                        <h3 class="text-xl font-semibold mb-3 text-indigo-600">对象导航</h3>
                        <p>JPA支持对象之间的导航关系，开发人员可以通过对象之间的关联来进行数据的操作和查询。</p>
                    </div>
                    <div class="bg-white p-6 rounded-xl shadow-md">
                        <h3 class="text-xl font-semibold mb-3 text-indigo-600">JPQL查询</h3>
                        <p>JPA提供了一种面向对象的查询语言（JPQL），开发人员可以使用类似SQL的语法来对持久化对象进行查询和操作。</p>
                    </div>
                    <div class="bg-white p-6 rounded-xl shadow-md">
                        <h3 class="text-xl font-semibold mb-3 text-indigo-600">持久化上下文</h3>
                        <p>JPA引入了持久化上下文的概念，用于管理实体对象的生命周期和状态变化，包括对象的加载、持久化、修改、删除等操作。</p>
                    </div>
                    <div class="bg-white p-6 rounded-xl shadow-md">
                        <h3 class="text-xl font-semibold mb-3 text-indigo-600">延迟加载</h3>
                        <p>JPA支持延迟加载机制，可以在需要时才从数据库中加载实体对象的关联数据，减少不必要的性能开销。</p>
                    </div>
                    <div class="bg-white p-6 rounded-xl shadow-md">
                        <h3 class="text-xl font-semibold mb-3 text-indigo-600">事务管理</h3>
                        <p>JPA提供了事务管理的支持，开发人员可以使用注解或者编程方式来管理事务，确保数据操作的一致性和完整性。</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Spring Data Introduction -->
        <section id="spring-data-intro" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">4. Spring Data 介绍</h2>
            </div>
            <div class="prose max-w-none text-gray-700">
                <p class="text-lg mb-6">Spring Data 是Spring 的一个子项目。用于简化数据库访问，支持<span class="text-red-600 font-semibold">NoSQL</span>和<span class="text-red-600 font-semibold">关系数据存储</span>。其主要目标是使数据库的访问变得方便快捷。</p>
                
                <div class="my-8">
                    <img src="https://cdn.nlark.com/yuque/0/2024/png/21449790/1707879284556-d9158097-8977-4aec-a850-bbc1f9c641da.png" alt="Spring Data架构图" class="w-full rounded-lg shadow-md hover-scale">
                </div>
                
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-indigo-600">SpringData 项目所支持 NoSQL 存储：</h3>
                        <ul class="space-y-2">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>MongoDB （文档数据库）</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>Redis（键/值存储）</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>HBase（列族数据库）</span>
                            </li>
                        </ul>
                    </div>
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-indigo-600">SpringData 项目所支持的关系数据存储技术：</h3>
                        <ul class="space-y-2">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>JDBC</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>JPA</span>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
        </section>

        <!-- Spring Data JPA Introduction -->
        <section id="spring-data-jpa-intro" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">5. Spring Data JPA介绍</h2>
            </div>
            <div class="prose max-w-none text-gray-700">
                <p class="text-lg mb-6">SpringDataJPA致力于减少数据访问层 (DAO) 的开发量。开发者唯一要做的，就只是声明持久层的接口，其他都交给 Spring Data JPA 来帮你完成。</p>
                <p class="mb-6">比如：当有一个 userDao.findUserById() 这样一个方法声明，大致应该能判断出这是根据给定条件的 ID 查询出满足条件的 User 对象。Spring Data JPA 做的便是规范方法的名字，根据符合规范的名字来确定方法需要实现什么样的逻辑。</p>
                
                <div class="my-8">
                    <img src="https://cdn.nlark.com/yuque/0/2024/png/21449790/1707879222269-c6aaed95-4a3c-4e19-a7fd-ae5d64e34d6c.png" alt="Spring Data JPA工作流程" class="w-full rounded-lg shadow-md hover-scale">
                </div>
            </div>
        </section>

        <!-- Environment Setup -->
        <section id="environment-setup" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">6. Spring Data JPA环境搭建</h2>
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <h3 class="text-2xl font-semibold mb-6">6.1 导入*.jar包</h3>
                <p class="mb-6">需要导入spring，hibernateJPA，SpringDataJPA的jar包</p>
                
                <h3 class="text-2xl font-semibold mb-6">6.2 定义接口</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>public interface IStudentDao extends Repository&lt;Student, Integer&gt; {
    // 根据名字查询对象
    public Student findStudentByName(String name);
}</code></pre>
                </div>
                
                <h3 class="text-2xl font-semibold mb-6">6.3 Spring整合Spring Data JPA</h3>
                <p class="mb-4">在Spring的配置文件中需要添加SpringDataJPA的约束文件</p>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>&lt;!-- 1.加载属性文件 location:指定文件文件的路径 --&gt;
&lt;context:property-placeholder location="classpath:jdbc.properties" /&gt;
&lt;!-- 2.数据源 --&gt;
&lt;bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"&gt;
    &lt;property name="driverClass" value="${jdbc.driver}"&gt;&lt;/property&gt;
    &lt;property name="jdbcUrl" value="${jdbc.url}"&gt;&lt;/property&gt;
    &lt;property name="user" value="${jdbc.username}"&gt;&lt;/property&gt;
    &lt;property name="password" value="${jdbc.password}"&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;!-- 2. 配置 JPA 的 EntityManagerFactory --&gt;
&lt;bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
    &lt;!-- 数据源 --&gt;
    &lt;property name="dataSource" ref="dataSource"&gt;&lt;/property&gt;
    &lt;!-- 扫描实体类 --&gt;
    &lt;property name="packagesToScan" value="com.ts.entity"&gt;&lt;/property&gt;
    &lt;!--JPA供应商适配 --&gt;
    &lt;property name="jpaVendorAdapter"&gt;
        &lt;bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"&gt;&lt;/bean&gt;
    &lt;/property&gt;
    &lt;!-- 配置hibernate的其他属性 --&gt;
    &lt;property name="jpaProperties"&gt;
        &lt;props&gt;
            &lt;prop key="hibernate.dialect"&gt;org.hibernate.dialect.MySQLDialect&lt;/prop&gt;
            &lt;prop key="hibernate.show_sql"&gt;true&lt;/prop&gt;
            &lt;prop key="hibernate.format_sql"&gt;true&lt;/prop&gt;
            &lt;prop key="hibernate.hbm2ddl.auto"&gt;update&lt;/prop&gt;
        &lt;/props&gt;
    &lt;/property&gt;
&lt;/bean&gt;
&lt;!-- 事务管理器 --&gt;
&lt;bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"&gt;
    &lt;property name="entityManagerFactory" ref="entityManagerFactory" /&gt;
&lt;/bean&gt;
&lt;!— Spring Data jpa的配置 
    base-package:dao层接口的包名
--&gt;
&lt;jpa:repositories base-package="com.ts.dao" entity-manager-factory-ref="entityManagerFactory"
    transaction-manager-ref="transactionManager" /&gt;
&lt;!-- 注册驱动 --&gt;
&lt;tx:annotation-driven transaction-manager="transactionManager" /&gt;</code></pre>
                </div>
                
                <div class="highlight-box mb-6">
                    <h4 class="font-bold text-xl mb-4 text-indigo-600"><i class="fas fa-info-circle mr-2"></i>重要概念</h4>
                    <p>LocalSessionFactoryBean和LocalContainerEntityManagerFactoryBean比较：</p>
                    <p class="mt-2">LocalSessionFactoryBean 得到的是SessionFactory，SessionFactory用来创建session来进行数据库的操作。</p>
                    <p class="mt-2">LocalContainerEntityManagerFactoryBean得到的是EntityManagerFactory用来创建EntityManager来进行数据库的操作</p>
                </div>
                
                <p class="mb-4">jpaVendorAdapter属性用于指明所使用的是哪一个厂商的JPA实现。Spring提供了多个JPA厂商适配器：</p>
                <ul class="mb-6 list-disc pl-6">
                    <li>EclipseLinkJpaVendorAdapter</li>
                    <li class="text-red-600 font-semibold">HibernateJpaVendorAdapter</li>
                    <li>OpenJpaVendorAdapter</li>
                    <li>TopLinkJpaVendorAdapter（在Spring 3.1版本中，已经将其废弃了）</li>
                </ul>
                
                <h3 class="text-2xl font-semibold mb-6">6.4 实体类对象</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>@Table(name="t_student")
@Entity
public class Student {
    /**
     * username:列名称
     * unique:是否唯一
     * nullable:是否为空
     * length:长度
     */
    @Column(name="username", unique=true,nullable=false,length=20)
    private String name;
    
    @Id // 主键
    @GeneratedValue(strategy=GenerationType.AUTO) // 主键生成策略
    private Integer id;
    
    private Integer age;
    
    private Date birthday;
}</code></pre>
                </div>
                
                <h3 class="text-2xl font-semibold mb-6">6.5 测试</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>public class SpringDataHello {
    private ApplicationContext ctx = null;
    private IStudentDao studentDao;
    {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        studentDao = ctx.getBean(IStudentDao.class);
    }
    @Test
    public void testFindStudentByName() {
        Student student = studentDao.findStudentByName("李四");
        System.out.println(studentDao.getClass());
        System.err.println(student); // 代理对象
    }
}</code></pre>
                </div>
            </div>
        </section>

        <!-- Repository Interface -->
        <section id="repository-interface" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">7. Repository接口</h2>
            </div>
            <div class="prose max-w-none text-gray-700">
                <ul class="list-disc pl-6 mb-6">
                    <li>Repository 是一个空接口. 即是一个标识接口</li>
                    <li><span class="font-semibold">若我们定义的接口(dao层)继承了 Repository或者子类，或者添加注解, 则该接口会被 IOC 容器识别为一个 Repository Bean(Proxy).放入到 IOC 容器中。</span>在该类中定义的方法必须要满足一定规范
                        <ul class="list-disc pl-6 mt-2">
                            <li>继承或者添加@RepositoryDefinition</li>
                            <li>要被JPA的注解扫到才会添加到Spring容器中</li>
                        </ul>
                    </li>
                    <li>也可以通过 @RepositoryDefinition 注解来替代继承 Repository 接口</li>
                </ul>
                
                <h3 class="text-2xl font-semibold mb-6">7.1 Repository 的子接口</h3>
                <ul class="list-disc pl-6 mb-6">
                    <li>Repository：最顶层的接口，是一个空的接口，目的是为了统一所有Repository的类型，且能让组件扫描的时候自动识别。</li>
                    <li>CrudRepository ：是Repository的子接口，提供CRUD的功能</li>
                    <li>PagingAndSortingRepository：是CrudRepository的子接口，添加分页和排序的功能</li>
                    <li class="text-red-600 font-semibold">JpaRepository</li>
                    <li>JpaSpecificationExecutor：用来做负责查询的接口</li>
                </ul>
                
                <h3 class="text-2xl font-semibold mb-6">7.2 Repository类中方法定义的规范</h3>
                <ul class="list-disc pl-6 mb-6">
                    <li>不是随便声明的. 而需要符合一定的规范</li>
                    <li>查询方法以 find | read | get 开头(比如 find、findBy、read、readBy、get、getBy)</li>
                    <li>涉及条件查询时，条件的属性用条件关键字连接，条件属性以首字母大写。</li>
                    <li>支持属性的级联查询. 若当前类有符合条件的属性, 则优先使用, 而不使用级联属性，若需要使用级联属性, 则属性之间使用 _ 进行连接</li>
                </ul>
                
                <p class="mb-6">举例说明：</p>
                <p class="mb-4">比如 findByUserAddressZip()。框架在解析该方法时，首先剔除 findBy，然后对剩下的属性进行解析，详细规则如下（此处假设该方法针对的域对象为 AccountInfo 类型）：</p>
                
                <div class="grid md:grid-cols-2 gap-6 mb-6">
                    <div>
                        <img src="https://cdn.nlark.com/yuque/0/2023/png/21449790/1692158558684-4dae556b-55c8-4e42-a851-1445b9c2c9b8.png" alt="方法解析规则" class="w-full rounded-lg shadow-md hover-scale">
                    </div>
                    <div>
                        <img src="https://cdn.nlark.com/yuque/0/2023/png/21449790/1692158558981-5aea76a3-119d-461b-9423-cf90e688536d.png" alt="方法解析示例" class="w-full rounded-lg shadow-md hover-scale">
                    </div>
                </div>
                
                <div class="highlight-box">
                    <h4 class="font-bold text-xl mb-4 text-indigo-600"><i class="fas fa-lightbulb mr-2"></i>注意事项</h4>
                    <p>可能会存在一种特殊情况，比如 AccountInfo 包含一个 user 的属性，也有一个 userAddress 属性，则优先使用当前类的属性, 而不使用级联属性. 若需要使用级联属性, 则属性之间使用 _ 进行连接。</p>
                </div>
            </div>
        </section>

        <!-- SpringBoot Integration -->
        <section id="springboot-integration" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">8. SpringBoot整合JPA</h2>
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <h3 class="text-2xl font-semibold mb-6">8.1 导入依赖</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>&lt;dependency&gt;
    &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
    &lt;artifactId&gt;lombok&lt;/artifactId&gt;
    &lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;/artifactId&gt;
    &lt;version&gt;2.1.7.RELEASE&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;mysql&lt;/groupId&gt;
    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
    &lt;version&gt;5.1.48&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
                </div>
                
                <h3 class="text-2xl font-semibold mb-6">8.2 YML配置</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf-8
    username: root
    password: root
  jpa:
    #这个参数是在建表的时候，将默认的存储引擎切换为 InnoDB 用的
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    #控制台显示SQL
    hibernate:
      #更新或者创建数据表结构
      ddl-auto: update
    show-sql: true</code></pre>
                </div>
                
                <h3 class="text-2xl font-semibold mb-6">8.3 创建实体类</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>package com.ts.application.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.omg.CORBA.INTERNAL;
import org.springframework.stereotype.Component;
import javax.persistence.*;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "t_user")
@Component
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
    private Integer id;
    @Column(length = 50)
    private String username;
    @Column(length = 50)
    private Integer age;
}</code></pre>
                </div>
                
                <div class="highlight-box mb-6">
                    <p class="text-red-600 font-semibold">注：springboot整合jpa项目中，创建完实体类后，因为ORM（对象映射关系）的缘故，可以通过运行项目，自动在数据库中创建对应表及字段</p>
                </div>
                
                <h3 class="text-2xl font-semibold mb-6">8.4 创建Mapper层</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>package com.ts.application.mapper;
 
import com.ts.application.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
 
@Repository //JpaRepository&lt;实体，主键类型&gt;
public interface UserRepository extends JpaRepository&lt;User, Integer&gt; {
}</code></pre>
                </div>
                
                <h3 class="text-2xl font-semibold mb-6">8.5 测试</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>@Autowired
UserRepository userRepository;

@Test
void test() {
    User user = new User();
    user.setUsername("toString");
    user.setAge(20);
    User save = userRepository.save(user);
    System.out.println(save);
}

@Test
void test2() {
    Optional&lt;User&gt; user = userRepository.findById(88);
    List&lt;User&gt; all = userRepository.findAll();
    System.out.println(all);
    System.out.println(user.get());
}</code></pre>
                </div>
            </div>
        </section>

        <!-- JPQL -->
        <section id="jpql" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">9. JPQL</h2>
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <h3 class="text-2xl font-semibold mb-6">9.1 JPQL是什么</h3>
                <p class="mb-6">JPQL全称Java Persistence Query Language，操作的是类和属性，其实就是跟HQL一样的。</p>
                
                <h3 class="text-2xl font-semibold mb-6">9.2 支持语法</h3>
                <p class="mb-4">JPQL提供的查询语法主要分为三类：</p>
                <ul class="list-disc pl-6 mb-6">
                    <li>查询用的 SELECT 语法</li>
                    <li>更新用的 UPDATE 语法</li>
                    <li>删除用的 DELETE 语法</li>
                </ul>
            </div>
        </section>

        <!-- @Query -->
        <section id="query-annotation" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">10. @Query查询</h2>
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <p class="mb-6">支持JPQL操作</p>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>@Query(value="select s1 from Student s1 where s1.id = (select max(s2.id)from Student s2)")
public Student getMaxIdStudent();</code></pre>
                </div>
                
                <p class="mb-6">支持原生的SQL</p>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>@Query(value="select s1.* from t_student s1 where s1.id = (select max(s2.id)from t_student s2)",nativeQuery=true)
public Student getMaxIdStudent();</code></pre>
                </div>
                
                <p class="mb-6">传递参数1：按照顺序</p>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>@Query("select s from Student s where  s.id = ?1 and s.name = ?2")
public Student findUser(Integer id,String name);</code></pre>
                </div>
                
                <p class="mb-6">传递参数2：按照名称</p>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>@Query("select s from Student s where  s.id = :id and s.name = :name")
public Student findUser2(@Param("name")String name,@Param("id")Integer id);</code></pre>
                </div>
                
                <p class="mb-6">模糊查询</p>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>@Query("select s from Student s where s.name like %:name%")
public Student findUser3(@Param("name")String name);</code></pre>
                </div>
            </div>
        </section>

        <!-- @Modifying -->
        <section id="modifying-annotation" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">11. @Modifying</h2>
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>@Modifying
@Query("update Student s set s.name = :name where s.id =:id")
public int updateUserUsername(@Param("id")Integer id,@Param("name")String name);</code></pre>
                </div>
                
                <div class="highlight-box">
                    <h4 class="font-bold text-xl mb-4 text-indigo-600"><i class="fas fa-exclamation-triangle mr-2"></i>注意事项</h4>
                    <ol class="list-decimal pl-6">
                        <li>可以通过JPQL完成DELETE和UPDATE操作，但是不能完成INSERT，因为JPQL不支持INSERT。</li>
                        <li>在@Query中编写更新语句必须要用@Modifying注解修饰，要通知SpringDataJPA这是一个更新操作。</li>
                        <li>在做更新操作的时候需要事务</li>
                        <li>默认情况下SpringDateJPA给每个方法都加事务，它们都是只读事务，不能完成更新。</li>
                    </ol>
                </div>
            </div>
        </section>

        <!-- JpaSpecificationExecutor -->
        <section id="jpa-specification-executor" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-2 h-12 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold">12. JpaSpecificationExecutor</h2>
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <p class="mb-6">不属于Repository体系，实现一组 JPA Criteria 查询相关的方法</p>
                <div class="my-8">
                    <img src="https://cdn.nlark.com/yuque/0/2023/png/21449790/1692158559328-2a1fa19e-6aac-433b-a332-edce2dd5c108.png" alt="JpaSpecificationExecutor方法" class="w-full rounded-lg shadow-md hover-scale">
                </div>
                
                <h3 class="text-2xl font-semibold mb-6">Repository</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>public interface IUserDao extends JpaRepository&lt;User, Integer&gt;,JpaSpecificationExecutor&lt;User&gt; {
}</code></pre>
                </div>
                
                <h3 class="text-2xl font-semibold mb-6">调用查询方法</h3>
                <div class="code-block text-gray-200 mb-6">
                    <pre><code>Pageable pageable = new PageRequest(2, 4);
Specification&lt;User&gt; spec = new Specification&lt;User&gt;() {
    /**
     * root: 代表查询的实体类. 
     * query: 查询条件
     * cb: 用于创建 Criteria 相关对象的工厂. 可以从中获取到 Predicate 对象
     * @return: *Predicate 类型, 代表一个查询条件. 
     */
    @Override
    public Predicate toPredicate(Root&lt;User&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder cb) {
        Path path1 = root.get("id");
        Path path2 = root.get("username");
        Path path3 = root.get("password");
        // Path&lt;Object&gt; path4 = root.get("user").get("id"); // 级联查询
        Predicate predicate = cb.equal(path1, 5);
        // Predicate predicate = cb.and(cb.gt(path2, 2),cb.gt(path3,3)); // 多条件查询
        return predicate ;
    }
};
Page&lt;User&gt; page = userDao.findAll(spec , pageable);</code></pre>
                </div>
            </div>
        </section>
    </main>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-8">
        <div class="container mx-auto px-6 max-w-6xl">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <h3 class="text-xl font-semibold text-white mb-2">技术小馆</h3>
                    <p class="text-gray-400">专业的Java技术知识分享平台</p>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" target="_blank" class="text-gray-300 hover:text-white transition duration-300">
                        <i class="fas fa-globe mr-2"></i>http://www.yuque.com/jtostring
                    </a>
                </div>
            </div>
            <div class="border-t border-gray-700 mt-6 pt-6 text-center text-gray-500 text-sm">
                &copy; 2024 技术小馆. All rights reserved.
            </div>
        </div>
    </footer>

    <!-- Mermaid JS -->
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>
```